# -*- coding: utf-8 -*-
# Trabalho de Inteligência Artificial
# Semestre 2009.2
# Mineração de Dados
# Implementação do algoritmo Simples

import orange

# Implementação do classificador no Orange

class Learner(object):
    def __new__(cls, examples=None, name="Simple", **kwds):
        learner = object.__new__(cls, **kwds)
        if examples:
            learner.__init__(name)
            return learner(examples)
        else:
            return learner

		# Define um nome para o classificador
    def __init__(self, name='Simple'):
        self.name = name

		# Chama o classificador
    def __call__(self, data):
        return Classifier(data)

class Classifier:
    def __init__(self, train, **kwds):
        self.__dict__ = kwds
        
				# Pré-processamento da entrada
        
        attributes = []
        for a in train.domain.attributes:
                attributes.append(a.name) 
        target_attr = train.domain.classVar.name
        attributes.append(target_attr)
        train_set = []
        k = 0
        for i in train:
                train_set.append([])
                for j in i:
				                train_set[k].append(j.value)
                k += 1
        self.target = target_attr
        self.data = train_set
        self.attributes = attributes
        self.classes = train.domain.classVar.values

    def model(self):
        # Calcula a frequência de cada atributo para cada classe
        freqs = {}
        for c in self.classes:
             freqs[c] = {}
             for a in self.attributes:
                   if a == self.target:
                        continue
                   else:
                        freqs[c][a] = {}
        for d in self.data:
             c = None
             for i in d:
                   if i in self.classes:
                        c = i
             for i in range(len(d)):
                   v = d[i]
                   if v == c:
                        continue
                   a = self.attributes[i]
                   if freqs[c][a].has_key(v):
                        freqs[c][a][v] += 1
                   else:
                        freqs[c][a][v] = 1
        # Computa os atributos mais frequentes para cada classe, formando modelos
        model = {}
        for c in self.classes:
             model[c] = []
             max = None
             for a in self.attributes:
                  if a == self.target:
                        continue
                  max = 0
                  max_attr = None
                  for k,v in freqs[c][a].items():
                        if v >= max:
                              max = v
                              max_attr = k
                  model[c].append(max_attr)
        return model
                      
             

		# Realiza a classificação de fato
    def __call__(self, example, resultType = orange.GetValue):
        test = []
        for i in example:
                if not i.value in self.classes:
                       test.append(i.value)

        # Pegamos os modelos para cada classe       
        model = self.model()

        # Calcula a pertinência do caso de teste em cada classe
        prob = []
        value = None
        max_pert = 0
        for c in self.classes:
               correct = 0
               for i in range(len(test)):
                     if test[i] == model[c][i]:
                             correct += 1
               pert = float(correct)/float(len(test))
               if pert >= max_pert:
                     max_pert = pert
                     value = c
               prob.append(pert)

        if resultType == orange.GetValue: 
                return value
        elif resultType == orange.GetProbabilities: 
                return orange.DiscDistribution(prob)
        else: 
                return (value, orange.DiscDistribution(prob))
